/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#include "stdafx.h"
#include "着色器.h"

#include "文件/file_载入保存数据.h"
using namespace std;


#define NV_EXTENSIONS




#include "shaderc/shaderc.hpp"

/*#ifdef _DEBUG 
#pragma comment(lib, "D:/U/DEV/VulkanSDK/Lib/glslangd.lib")
#pragma comment(lib, "D:/U/DEV/VulkanSDK/Lib/glslang-default-resource-limitsd.lib")
#pragma comment(lib, "D:/U/DEV/VulkanSDK/Lib/shadercd.lib")
#pragma comment(lib, "D:/U/DEV/VulkanSDK/Lib/shaderc_combinedd.lib")
#else
#pragma comment(lib, "D:/U/DEV/VulkanSDK/Lib/glslang.lib")
#pragma comment(lib, "D:/U/DEV/VulkanSDK/Lib/glslang-default-resource-limits.lib")
#pragma comment(lib, "D:/U/DEV/VulkanSDK/Lib/shaderc.lib")
#pragma comment(lib, "D:/U/DEV/VulkanSDK/Lib/shaderc_combined.lib")
#endif*/



//#include "SPIRV/GlslangToSpv.h"
//#include <MoltenVKGLSLToSPIRVConverter/GLSLToSPIRVConverter.h>



bool f_bd_GLSLtoSPV(E_着色阶段 阶段, const string code, const string 保存路径) {
	/*shaderc::Compiler 编译器;

	shaderc_shader_kind shaderStage;

	switch (f_vk_get参数布局着色阶段(阶段)) {
	case VK_SHADER_STAGE_VERTEX_BIT:
		shaderStage = shaderc_vertex_shader;
		break;
	case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:
		shaderStage = shaderc_tess_control_shader;
		break;
	case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:
		shaderStage = shaderc_tess_evaluation_shader;
		break;
	case VK_SHADER_STAGE_GEOMETRY_BIT:
		shaderStage = shaderc_geometry_shader;
		break;
	case VK_SHADER_STAGE_FRAGMENT_BIT:
		shaderStage = shaderc_fragment_shader;
		break;
	case VK_SHADER_STAGE_COMPUTE_BIT:
		shaderStage = shaderc_compute_shader;
		break;
	case VK_SHADER_STAGE_RAYGEN_BIT_NV:
		shaderStage = shaderc_raygen_shader;
		break;
	case VK_SHADER_STAGE_ANY_HIT_BIT_NV:
		shaderStage = shaderc_anyhit_shader;
		break;
	case VK_SHADER_STAGE_TASK_BIT_NV:
		shaderStage = shaderc_task_shader;
		break;
	case VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR:
		shaderStage = shaderc_glsl_closesthit_shader;
		break;
	case VK_SHADER_STAGE_CALLABLE_BIT_KHR:
		shaderStage = shaderc_glsl_callable_shader;
		break;
	case VK_SHADER_STAGE_MESH_BIT_NV:
		shaderStage = shaderc_mesh_shader;
		break;
	default:
		shaderStage = shaderc_spirv_assembly;
		break;
	}

	auto r = 编译器.CompileGlslToSpv(code, shaderStage, 保存路径.c_str());*/

	return true;
}






inline uint32 S_Vk着色器创建参数::f_get着色阶段(uint32 id) {
	switch (m_参数布局[id].m_着色阶段) {
	case E_着色阶段::e_顶点着色:
		return VK_SHADER_STAGE_VERTEX_BIT;

	case E_着色阶段::e_细分控制着色:
		return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;

	case E_着色阶段::e_细分着色:
		return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;

	case E_着色阶段::e_几何着色:
		return VK_SHADER_STAGE_GEOMETRY_BIT;

	case E_着色阶段::e_像素着色:
		return VK_SHADER_STAGE_FRAGMENT_BIT;

	case E_着色阶段::e_计算着色:
		return VK_SHADER_STAGE_COMPUTE_BIT;
	default:
		break;
	}
	return -1;
}

inline uint32 S_Vk着色器创建参数::f_get参数类型(uint32 id) {
	return f_vk_get缓存布局类型(m_参数布局[id].m_参数类型);
	switch (m_参数布局[id].m_参数类型) {
	case E_板载缓存类型::e_UBO:
		return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
		break;
	case E_板载缓存类型::e_VBO:
	case E_板载缓存类型::e_SSBO:
		return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
		break;
	case E_板载缓存类型::e_SSBOd:
		return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
		//case E_板载缓存类型::e_UBO:
		//	return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;

	case E_板载缓存类型::e_IMAGE: return VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
	case E_板载缓存类型::e_IMAGE_SAMPLER: return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;

	case E_板载缓存类型::e_光追BVH: return VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
	default:
		break;
	}

	return -1;
}


void f_vkShader_创建着色器(S_Vk着色* shader, std::string path, E_着色阶段 阶段, uint32 id, bool 光追着色创建, uint32 着色ID) {
	//auto code = f_读文本文件(path);
	std::cout<<"r shader file : "<< id << " " << path << std::endl;
	auto code = f_读文件<uint8>(path);

	auto* 着色阶段创建信息 = &shader->m_着色阶段创建信息[id];
	(*着色阶段创建信息) = {};
	着色阶段创建信息->sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
	着色阶段创建信息->pNext = 0;
	着色阶段创建信息->pSpecializationInfo = 0;
	着色阶段创建信息->pName = "main";

	switch (阶段) {
	case E_着色阶段::e_顶点着色:
		着色阶段创建信息->stage = VK_SHADER_STAGE_VERTEX_BIT;
		break;
	case E_着色阶段::e_几何着色:
		着色阶段创建信息->stage = VK_SHADER_STAGE_GEOMETRY_BIT;
		break;
	case E_着色阶段::e_像素着色:
		着色阶段创建信息->stage = VK_SHADER_STAGE_FRAGMENT_BIT;
		break;
	case E_着色阶段::e_计算着色:
		着色阶段创建信息->stage = VK_SHADER_STAGE_COMPUTE_BIT;
		break;
	case E_着色阶段::e_光追射线生成:
		着色阶段创建信息->stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR;
		break;
	case E_着色阶段::e_光追忽略相交:
		着色阶段创建信息->stage = VK_SHADER_STAGE_MISS_BIT_KHR;
		break;
	case E_着色阶段::e_光追最近相交:
		着色阶段创建信息->stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
		break;
	case E_着色阶段::e_光追回调:
		着色阶段创建信息->stage = VK_SHADER_STAGE_CALLABLE_BIT_KHR;
		break;
	default:
		break;
	}




	VkShaderModuleCreateInfo 着色模型创建信息 = {};
	着色模型创建信息.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
	着色模型创建信息.pNext = 0;
	着色模型创建信息.flags = 0;
	着色模型创建信息.codeSize = code.size() * sizeof(uint8);
	着色模型创建信息.codeSize = (着色模型创建信息.codeSize / 4) * 4;
	着色模型创建信息.pCode = reinterpret_cast<const uint32*>(code.data());



	VkResult res = vkCreateShaderModule(shader->m_设备, &着色模型创建信息, NULL, &(着色阶段创建信息->module));
	if (res != VK_SUCCESS) {
		std::cout<<"vkCreateShaderModule error:"<< res << std::endl;
	}


	if (光追着色创建) {
		uint32 num = shader->m_光追着色组创建信息.size();
		if (id >= num) {
			for (uint32 i = num; i <= id; ++i) {
				VkRayTracingShaderGroupCreateInfoKHR 光追着色组{};
				光追着色组.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR;
				光追着色组.closestHitShader		= VK_SHADER_UNUSED_KHR;
				光追着色组.anyHitShader			= VK_SHADER_UNUSED_KHR;
				光追着色组.intersectionShader	= VK_SHADER_UNUSED_KHR;
				光追着色组.generalShader		= VK_SHADER_UNUSED_KHR;

				shader->m_光追着色组创建信息.push_back(光追着色组);
			}
		}

		VkRayTracingShaderGroupCreateInfoKHR& 光追着色组 = shader->m_光追着色组创建信息[id];
		光追着色组.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR;
		光追着色组.closestHitShader		= VK_SHADER_UNUSED_KHR;
		光追着色组.anyHitShader			= VK_SHADER_UNUSED_KHR;
		光追着色组.intersectionShader	= VK_SHADER_UNUSED_KHR;
		光追着色组.generalShader		= VK_SHADER_UNUSED_KHR;
		switch (阶段) {
		case E_着色阶段::e_光追回调:
		case E_着色阶段::e_光追射线生成:
		case E_着色阶段::e_光追忽略相交:
			//光追着色组.generalShader		= shader->m_光追着色组创建信息.size();
			光追着色组.generalShader		= 着色ID;
			光追着色组.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
			break;
		case E_着色阶段::e_光追最近相交:
			//光追着色组.closestHitShader		= m_光追着色组创建信息.size();
			光追着色组.closestHitShader		= 着色ID;
			光追着色组.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR;
			break;
		default:
			break;
		}
	}

	shader->m_光追着色器[id].m_Type = 阶段;
}

void f_vkShader_销毁着色器(S_Vk着色* shader, uint32 id, bool 光追着色创建) {
	vkDestroyShaderModule(shader->m_设备, shader->m_着色阶段创建信息[id].module, 0);

	if (光追着色创建) {
		//shader->m_光追着色器.erase(shader->m_光追着色器.begin() + id);
		//shader->m_着色阶段创建信息.erase(shader->m_着色阶段创建信息.begin() + id);
		//shader->m_光追着色组创建信息.erase(shader->m_光追着色组创建信息.begin() + id);
	}
	
}



struct S_Vk着色器顶点输入数据参数 : public S_着色顶点输入参数 {

	uint32 f_添加顶点输入配置(S_着色顶点输入参数& 顶点输入配置) {
		m_绑定位置 = 0;
		m_元素大小 = 顶点输入配置.m_元素大小;
		m_输入数据类型 = VK_VERTEX_INPUT_RATE_VERTEX;
		m_数据格式 = E_数据格式::e_F_RGB;

	}
};


S_Vk着色::S_Vk着色(VkDevice& 设备, uint32 阶段数量, string name) :S_着色(name), m_设备(设备) {
	m_着色阶段创建信息.resize(阶段数量);
	m_光追着色器.resize(阶段数量);
}

S_Vk着色::~S_Vk着色() {
	vkDestroyDescriptorPool(m_设备, m_参数池, nullptr);

	for (auto& e : m_着色阶段创建信息) {
		vkDestroyShaderModule(m_设备, e.module, 0);
	}

	for (auto& e : m_参数布局) {
		vkDestroyDescriptorSetLayout(m_设备, e, 0);
	}
	
	vkDestroyPipelineLayout(m_设备, m_线管布局, 0);

}


void S_Vk着色::f_create布局描述设置(const S_线管创建配置& 参数) {
	vector<VkDescriptorSetLayoutBinding>	布局绑定;
	vector<VkDescriptorPoolSize>			描述池大小;
	布局绑定.reserve(参数.m_参数布局.size());
	描述池大小.reserve(参数.m_参数布局.size());

	for (auto& e : 参数.m_参数布局) {
		VkDescriptorSetLayoutBinding lb{};
		lb.binding = e.m_绑定位置;
		
		lb.descriptorType = f_vk_get缓存布局类型(e.m_参数类型);

		if (e.m_参数类型 == E_板载缓存类型::e_SAMPLER_Array) {
			lb.descriptorCount = 128;
		}
		else {
			lb.descriptorCount = 1;
		}

		lb.stageFlags = f_vk_get参数布局着色阶段(e.m_着色阶段);
		布局绑定.push_back(lb);

		VkDescriptorPoolSize ps;
		ps.type = lb.descriptorType;
		ps.descriptorCount = 1;
		描述池大小.push_back(ps);
	}
	std::cout << "CreateDescriptorSetLayout" << std::endl;
	m_参数布局.resize(1);
	m_参数布局[0] = f_vk_创建着色器参数布局设置(m_设备, 布局绑定);


	std::cout << "vkCreateDescriptorPool" << std::endl;
	VkDescriptorPoolCreateInfo 描述池创建信息 = {};
	描述池创建信息.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
	描述池创建信息.pNext = 0;
	描述池创建信息.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
	描述池创建信息.maxSets = 1;
	描述池创建信息.poolSizeCount = 描述池大小.size();
	描述池创建信息.pPoolSizes = 描述池大小.data();
	auto res = vkCreateDescriptorPool(m_设备, &描述池创建信息, 0, &m_参数池);
	if (res != VK_SUCCESS) {
		std::cout<<"error : vkCreateDescriptorPool" << res << std::endl;
	}

}

void S_Vk着色::f_init着色参数布局(const S_线管创建配置& 参数配置) {
	auto res = 0;

	S_Vk着色器创建参数 参数(参数配置);
	f_create布局描述设置(参数配置);
	
	std::vector<VkPushConstantRange> 常量区间;
	for (auto& e : 参数配置.m_常量偏移和字节数) {
		常量区间.push_back({
			f_vk_get参数布局着色阶段(e.阶段),
			e.偏移,
			e.字节数
		});
	}


	VkPipelineLayoutCreateInfo 线管布局创建信息;
	线管布局创建信息.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
	线管布局创建信息.pNext = 0;
	线管布局创建信息.flags = 0;
	线管布局创建信息.pPushConstantRanges = 常量区间.data();
	线管布局创建信息.pushConstantRangeCount = 常量区间.size();
	线管布局创建信息.pSetLayouts = m_参数布局.data();
	线管布局创建信息.setLayoutCount = 1;
	res = vkCreatePipelineLayout(m_设备, &线管布局创建信息, 0, &m_线管布局);
	if (res != VK_SUCCESS) {
		std::cout<<"vkCreatePipelineLayout"<<std::endl;
	}



	/////////////////////////////////////////////////////////////////
	//                        顶点绑定信息                         //
	/////////////////////////////////////////////////////////////////
	//VkVertexInputBindingDescription 顶点绑定信息 = {};
	uint32 顶点输入配置数量 = 参数.f_get输入数量();
	if (顶点输入配置数量) {
		m_顶点绑定信息.resize(顶点输入配置数量);
		m_管线的顶点输入属性描述.resize(顶点输入配置数量);

		uint32 offset = 0;
		for (uint32 i = 0; i < 顶点输入配置数量; ++i) {
			m_管线的顶点输入属性描述[i].location = i;
			m_管线的顶点输入属性描述[i].binding = 0;
			m_管线的顶点输入属性描述[i].format = (VkFormat)f_get数据格式(参数.m_顶点配置[i].m_数据格式);
			m_管线的顶点输入属性描述[i].offset = offset;

			offset += 参数.f_get输入顶点间隔(i);
		}

		m_顶点绑定信息[0].binding = 0;
		m_顶点绑定信息[0].inputRate = (VkVertexInputRate)参数.f_get输入顶点类型(0);
		m_顶点绑定信息[0].stride = offset;// 参数.f_get输入顶点间隔(i);



		m_线管顶点输入状态创建信息.vertexBindingDescriptionCount = 1;
		m_线管顶点输入状态创建信息.pVertexBindingDescriptions = m_顶点绑定信息.data();
		m_线管顶点输入状态创建信息.vertexAttributeDescriptionCount = 顶点输入配置数量;
		m_线管顶点输入状态创建信息.pVertexAttributeDescriptions = m_管线的顶点输入属性描述.data();
	}
	else {
		m_线管顶点输入状态创建信息.vertexBindingDescriptionCount = 0;
		m_线管顶点输入状态创建信息.pVertexBindingDescriptions = 0;
		m_线管顶点输入状态创建信息.vertexAttributeDescriptionCount = 0;
		m_线管顶点输入状态创建信息.pVertexAttributeDescriptions = 0;
	}
	//VkPipelineVertexInputStateCreateInfo 线管顶点输入状态创建信息;
	m_线管顶点输入状态创建信息.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
	m_线管顶点输入状态创建信息.pNext = NULL;
	m_线管顶点输入状态创建信息.flags = 0;
	
}

void S_Vk着色::f_initRT着色参数布局(const S_线管创建配置& 参数配置) {
	std::cout<<"Vulkan init ray DescriptorSetLayout"<<std::endl;
	f_create布局描述设置(参数配置);
}

void S_Vk着色::f_alloc参数设置(S_结构对象指针* 描述集列表) {
	m_描述集列表分配信息 = {};
	m_描述集列表分配信息.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
	m_描述集列表分配信息.pNext = 0;
	m_描述集列表分配信息.descriptorPool = m_参数池;
	m_描述集列表分配信息.descriptorSetCount = m_参数布局.size();
	m_描述集列表分配信息.pSetLayouts = m_参数布局.data();
	
	auto res = vkAllocateDescriptorSets(m_设备, &m_描述集列表分配信息, (VkDescriptorSet*)描述集列表);
	if (res != VK_SUCCESS) {
		std::cout << "vkAllocateDescriptorSets error" << std::endl;
		//exit(-1);
	}
}

void S_Vk着色::f_free参数设置(S_结构对象指针* 描述集列表) {
	auto res = vkFreeDescriptorSets(m_设备, m_参数池, 1, (VkDescriptorSet*)描述集列表);
	assert(res == VK_SUCCESS);
}


/*vector<VkPipelineShaderStageCreateInfo> S_Vk着色::f_取着色阶段创建信息() {
	vector<VkPipelineShaderStageCreateInfo> 阶段创建信息;

	for (auto& e : m_光追着色器) {
		阶段创建信息.push_back(e.m_着色阶段创建信息);
	}

	return 阶段创建信息;
}*/



void S_Vk着色::f_从文件载入着色器(std::string path, E_着色阶段 阶段, uint8 id, bool 光追着色创建) {
	f_vkShader_创建着色器(this, path, 阶段, id, 光追着色创建, id);
	/*auto code = f_读文件<uint8>(path);

	auto* 着色阶段创建信息 = &m_着色阶段创建信息[id];
	(*着色阶段创建信息) = {};
	着色阶段创建信息->sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
	着色阶段创建信息->pNext = 0;
	着色阶段创建信息->pSpecializationInfo = 0;
	着色阶段创建信息->pName = "main";
	
	switch (阶段) {
		case E_着色阶段::e_顶点着色:
			着色阶段创建信息->stage = VK_SHADER_STAGE_VERTEX_BIT;
			break;
		case E_着色阶段::e_几何着色:
			着色阶段创建信息->stage = VK_SHADER_STAGE_GEOMETRY_BIT;
			break;
		case E_着色阶段::e_像素着色:
			着色阶段创建信息->stage = VK_SHADER_STAGE_FRAGMENT_BIT;
			break;
		case E_着色阶段::e_计算着色:
			着色阶段创建信息->stage = VK_SHADER_STAGE_COMPUTE_BIT;
			break;
		case E_着色阶段::e_光追射线生成:
			着色阶段创建信息->stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR;
			break;
		case E_着色阶段::e_光追忽略相交:
			着色阶段创建信息->stage = VK_SHADER_STAGE_MISS_BIT_KHR;
			break;
		case E_着色阶段::e_光追最近相交:
			着色阶段创建信息->stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
			break;
		case E_着色阶段::e_光追回调:
			着色阶段创建信息->stage = VK_SHADER_STAGE_CALLABLE_BIT_KHR;
			break;
	default:
		break;
	}

	


	VkShaderModuleCreateInfo 着色模型创建信息 = {};
	着色模型创建信息.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
	着色模型创建信息.pNext = 0;
	着色模型创建信息.flags = 0;
	着色模型创建信息.codeSize = code.size() * sizeof(uint8);
	着色模型创建信息.pCode = reinterpret_cast<const uint32*>(code.data());



	VkResult res = vkCreateShaderModule(m_设备, &着色模型创建信息, NULL, &(着色阶段创建信息->module));
	assert(res == VK_SUCCESS);


	if (光追着色创建) {
		VkRayTracingShaderGroupCreateInfoKHR 光追着色组{};
		光追着色组.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR;
		光追着色组.closestHitShader		= VK_SHADER_UNUSED_KHR;
		光追着色组.anyHitShader			= VK_SHADER_UNUSED_KHR;
		光追着色组.intersectionShader	= VK_SHADER_UNUSED_KHR;
		光追着色组.generalShader		= VK_SHADER_UNUSED_KHR;
		switch (阶段) {
		case E_着色阶段::e_光追回调:
		case E_着色阶段::e_光追射线生成:
		case E_着色阶段::e_光追忽略相交:
			光追着色组.generalShader		= m_光追着色组创建信息.size();
			光追着色组.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
			break;
		case E_着色阶段::e_光追最近相交:
			//光追着色组.closestHitShader		= m_光追着色组创建信息.size();
			光追着色组.closestHitShader		= 2;
			光追着色组.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR;
			break;
		default:
			break;
		}

		m_光追着色组创建信息.emplace_back(光追着色组);
	}
	

	m_光追着色器[id].m_Type = 阶段;*/
}

/*void S_Vk着色::f_销毁着色器(uint32 id) {
	if (id < m_着色阶段创建信息.size()) {
		vkDestroyShaderModule(m_设备, m_着色阶段创建信息[id].module, 0);

		m_着色阶段创建信息.erase(m_着色阶段创建信息.begin() + id);
		m_光追着色组创建信息.erase(m_光追着色组创建信息.begin() + id);
	}
}*/









